﻿/*
 * Project: IV:MP GUI Editor (http://code.google.com/p/ivmp-gui-editor)
 * Code license: GNU Lesser GPL (http://www.gnu.org/copyleft/lesser.html)
 * 
 * Authors: CrackHD
 * Description: EDocument class (stored in ETab's Content) used to work with text/script files (TextBox is needed).
 */

using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Highlighting;
using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace IvmpEditor
{
    public class EDocument : ITab
    {
        // Fields:
        public readonly ETab Tab;
        public FileInfo File;
        public DocumentFileExtension Type;
        public Encoding TextEncoding;
        public readonly TextEditor TextBox;
        public readonly FindReplace.IEditor FindReplaceAdapter;

        // Constructors:
        public EDocument(ETab editorTab, FileInfo file, DocumentFileExtension newFileExtension = null, string name = "New")
        {
            IsDesiredNew = (file == null);

            Tab = editorTab;
            if (!IsDesiredNew)
                Type = SupportedFileTypes.GetByExtension(file.Extension);
            else
            {
                Type = newFileExtension ?? SupportedFileTypes.Squirrel;
                file = new FileInfo(name + Type.Extensions[0]);
            }
            File = file;

            // Init TextEditor control:
            TextBox = new TextEditor();
            TextBox.FontFamily = new System.Windows.Media.FontFamily("Consolas");
            TextBox.FontSize = 13.3d;
            TextBox.VerticalAlignment = VerticalAlignment.Stretch;
            TextBox.HorizontalAlignment = HorizontalAlignment.Stretch;
            TextBox.ShowLineNumbers = true;
            SetCodeEditorHighlighting(TextBox, this.Type);

            // Init FindReplace adapter for this document text editor:
            FindReplaceAdapter = new FindReplace.TextEditorAdapter(this.TextBox);

            // Load content for this document:
            if (IsDesiredNew)
            {
                // Set the default encoding to utf-8
                TextEncoding = System.Text.Encoding.Default;
                Text =
@"/* TODO: It's blank file created from template. Write your code or open existing file!

This is a testing build of IV:MP GUI Editor. Regulary check for updates (menu command).
GUI Editor, functions list and some other features are not finished.
Please do not use advanced/unfinished features, they can cause crash in some cases.

Thanks!
 */
";
            }
            else
                LoadFromFile();
            IsSaved = true;
        }

        // Properties:
        public string Text
        {
            // Gets or sets a text inside document
            get { return TextBox.Text; }
            set { TextBox.Text = value; }
        }
        public bool IsSaved { get; set; }
        public bool IsDesiredNew { get; set; }
        /*bool ITab.IsChangeable
        {
            get { return TextBox.IsReadOnly; }
            set { TextBox.IsReadOnly = value; }
        }*/
        string ITab.Name { get { return File.Name; } }

        // Methods:
        public void Focus()
        {
            this.TextBox.Focus();
        }
        void ITab.SetupEvents()
        {
            TextBox.TextChanged += delegate
            {
                IsSaved = false;
                if (!Tab.TabHeader.EndsWith("*"))
                    Tab.TabHeader += '*';
                Tab.TabPage.UpdateLayout();
            };
        }

        void LoadFromFile()
        {
            // Open stream and read all bytes
            var buff = new byte[File.Length];
            using (var stream = File.OpenRead())
                stream.Read(buff, 0, buff.Length);

            // Try to detect encoding:
            var charDet = new Mozilla.CharDet.UniversalDetector();
            charDet.HandleData(buff);
            charDet.DataEnd();
            if (charDet.DetectedCharsetName == null)
            {
                // File length is too short to detect any encoding, or detect failed.
                TextEncoding = Encoding.Default;
            }
            else
            {
                // Detected encoding:
                this.TextEncoding = Encoding.GetEncoding(charDet.DetectedCharsetName);
            }
            IsSaved = true;
            Text = this.TextEncoding.GetString(buff);
        }
        public bool Save()
        {
            if (IsDesiredNew == false)
            {
                try
                {
                    using (var stream = new FileStream(File.FullName, FileMode.Create, FileAccess.Write))
                    using (var writer = new StreamWriter(stream, this.TextEncoding))
                        writer.Write(this.Text);

                    // Push this file name into the top of recent files history
                    Tab.Editor.MainWindow.UpdateRecentFiles( Settings.AddRecentFilesTop(File.FullName) );

                    Tab.TabHeader = File.Name;
                    IsSaved = true;
                    return true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format(Properties.Resources.L_FileWriteFailure, this.File, Environment.NewLine,  ex.Message), 
                        string.Format(Properties.Resources.L_ErrorU, ex.GetType().Name), MessageBoxButton.OK);
                    return false;
                }
            }
            else
            {
                // If this is new file, show dialog to choose where to save
                if (ShowSaveAsDialog())
                    return Save();
                else return false;
            }
        }
        public bool ShowSaveAsDialog()
        {
            // Offer to choose file name.
            // TODO: move dialog code to wndMain 
            var dg = new System.Windows.Forms.SaveFileDialog();
            dg.InitialDirectory = File.DirectoryName;
            if (IsDesiredNew == false)
                dg.FileName = File.Name.Substring(0, File.Name.Length - File.Extension.Length);    // name without extension
            dg.Filter = SupportedFileTypes.GetFilterList(false, false, false);
            dg.Title = Properties.Resources.L_SaveAs;
            dg.AddExtension = true;
            if (dg.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                return false;

            // Changing filename.
            File = new FileInfo(dg.FileName);
            IsDesiredNew = false;

            // Handle type change.
            this.Type = SupportedFileTypes.GetByExtension(File.Extension);
            SetCodeEditorHighlighting(TextBox, Type);

            return true;
        }

        // Statics:
        public static void SetCodeEditorHighlighting(TextEditor avalonEdit, DocumentFileExtension scriptType)
        {
            foreach (var hd in HighlightingManager.Instance.HighlightingDefinitions)
                if (hd.Name == scriptType.HighlightingScheme)
                    avalonEdit.SyntaxHighlighting = hd;

            // TODO: Allow custom highlighting schemas in app dir?
            /* string dir = Path.GetFullPath(@".\distrib\");
            string fname = dir + highlightingScheme + "-Mode.xshd";
            if (File.Exists(fname))
                using (Stream s = File.OpenRead(fname))
                {
                    using (XmlTextReader reader = new XmlTextReader(s))
                        avalonEdit.SyntaxHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load
                                (reader, ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance);
                }
            else avalonEdit.SyntaxHighlighting = null; */
        }
    }
}